iT邦幫忙

2023 iThome 鐵人賽

DAY 5
0
Mobile Development

App從開發到上架系列 第 5

Day5: iOS 開發:客製化元件 - CustomTabBarView

  • 分享至 

  • xImage
  •  

今天要開始製作做畫面了!,這個App會有五個畫面,分別是:

  1. 主頁
  2. 尋找附近餐廳
  3. 錢包
  4. 消息
  5. 會員資料

TabBar

在這五頁,每一頁最底下都會有一個TabBar去做換頁,這邊先來快速複習什麼叫做TabBar:

  1. What is.... ?
    他是一個出現在App底下的欄,提供在不同頁面之間快速地切換。
  2. Why use....?
    TabBar是可以把資料扁平化,讓用户節省一層又一層的尋找時間。同時提供了前往多個不同的ViewController功能。

CustomTabBar

為什麼需要客製化?好處在哪?跟系統提供的差別在哪裡?

  1. 先會做成客製化是因為之前做的案子有這個需求,之後我在做Side Project也覺得這個方式不錯,所以就沒有用系統提供的了。

  2. 做客製化的好處當然就是自由度高,你可以讓他變成你喜歡的樣子,因為沒有了原生系統的限制,所以做出來的成品就會最貼近你的需求

  3. 這邊列出客製化與系統提供的主要差異:

    1. 客製化:
      • 優點:
        自由度高,能接近自己的需求
      • 缺點:
        做的時候比較麻煩費時
    2. Apple原生:
      • 優點:
        很快就有一個樣子了,能快速做出來
      • 缺點:
        如遇到一些特殊需求比較會不能滿足

所以使用客製化跟原生沒有一定哪個比較好,我覺得都是看需求而定~

原生的網路上都很多教學了,所以我想做一個是自己客製的:

結構有點像是這樣,原諒我不太會畫圖...
https://ithelp.ithome.com.tw/upload/images/20230920/20140368L4TCIvti3T.png

首先我們先點擊 New File -> 選擇Cocoa Touch Class ->類別選擇ViewController,並且把 "also create xib"給打勾。

https://ithelp.ithome.com.tw/upload/images/20230920/20140368v03Xknik47.png![]https://ithelp.ithome.com.tw/upload/images/20230920/20140368xOf32D0QCb.png
因為我們這是客製化的UIView,所以我們需要改一些設定

class 你的ViewController名稱: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
    }
}

把上面的Class繼承的UIViewController換成UIView,並把viewDidLoad換掉,最後會是這樣:

class 你的ViewController名稱: UIView {

    override func awakeFromNib() {
        super.awakeFromNib()
    }
}

swift檔案就設定好了,接著去到Xib,首先把file's owner取消掉:

https://ithelp.ithome.com.tw/upload/images/20230920/20140368KQpBQle1ua.png

然後把Size設定成 Freedom:

https://ithelp.ithome.com.tw/upload/images/20230920/20140368ZsHgmpkusr.png

接著就把它弄成正方形的,並把元件設定好,大小無所謂,因為最終決定大小的是最後出現在ViewController的TabBar。

(imageView要在Button的下面喔,不然會點不到,一點圖層概念)
https://ithelp.ithome.com.tw/upload/images/20230920/201403687hBkigaAgb.png

好了之後就可以寫程式了:
import UIKit

class CustomTabBarView: UIView {
    
    @IBOutlet weak var navgiationBtn: UIButton!
    @IBOutlet weak var titleLb: UILabel!
    @IBOutlet weak var viewControllerImg: UIImageView!
    
    var delegate: CustomViewListener?
    var stringTag: Int?
    
    var buttonTapped: ((Int) -> ())? = nil

    
    override func awakeFromNib() {
       addXibView()
    }
    
    @IBAction func didTapBtn(_ sender: Any) {
        delegate?.target?(stringTag: stringTag ?? 0)
    }
    
    func setInit(tag: Int, text: String, image: UIImage) {
        viewControllerImg.image = image
        titleLb.text = text
        stringTag = tag
    }

}

fileprivate extension CustomTabBarView {
    //加入畫面
    func addXibView() {
        
        if let loadView = Bundle(for: CustomTabBarView.self).loadNibNamed("CustomTabBarView", owner: self, options: nil)?.first as? UIView{
            addSubview(loadView)
            loadView.frame = bounds
        }
        navgiationBtn.setTitle("", for: .normal)
    }
}
@objc protocol CustomViewListener: NSObjectProtocol {
    @objc optional func target(stringTag:Int)
}

建立長條的TabBar裡面裝剛剛的Button:

方法跟剛剛一樣,好了之後讓「每個UIView都繼承剛剛的客製化按鈕的Class:
https://ithelp.ithome.com.tw/upload/images/20230920/20140368OO6qKmI2NL.png##### 程式碼:

enum BottomItems: Int, CaseIterable {
    case HomeViewController = 0, FindingViewController, WalletViewController, NewsViewController, MemberShipViewController

    var title: String{
        switch self {
        case .HomeViewController:
            return NSLocalizedString("HomeViewController", comment: "")
        case .FindingViewController:
            return NSLocalizedString("FindingViewController", comment: "")
        case .WalletViewController:
            return NSLocalizedString("WalletViewController", comment: "")
        case .NewsViewController:
            return NSLocalizedString("NewsViewController", comment: "")
        case .MemberShipViewController:
            return NSLocalizedString("MemberShipViewController", comment: "")
        }
    }
    
}

class CustomTabBar: UIView {

    @IBOutlet weak var homeView: CustomTabBarView!
    @IBOutlet weak var findingView: CustomTabBarView!
    @IBOutlet weak var walletView: CustomTabBarView!
    @IBOutlet weak var newsView: CustomTabBarView!
    @IBOutlet weak var membershipView: CustomTabBarView!
    
    var buttonTapped: ((Int) -> ())? = nil
    var items = BottomItems.allCases

    
    override func awakeFromNib() {
        super.awakeFromNib()
        addXibView()
    }
}

extension CustomTabBar: CustomViewListener {
    func target(stringTag: Int) {
        buttonTapped?(items[stringTag].rawValue)
    }
}

fileprivate extension CustomTabBar {
    //加入畫面
    func addXibView() {
        if let loadView = Bundle(for: CustomTabBar.self).loadNibNamed("CustomTabBar", owner: self, options: nil)?.first as? UIView{
            addSubview(loadView)
            loadView.frame = bounds
        }
        homeView.delegate = self
        findingView.delegate = self
        walletView.delegate = self
        newsView.delegate = self
        membershipView.delegate = self
        
        homeView.setInit(tag: 0, text: "home", image: UIImage(systemName: "house")!)
        findingView.setInit(tag: 1, text: "finding", image: UIImage(systemName: "magnifyingglass")!)
        walletView.setInit(tag: 2, text: "wallet", image: UIImage(systemName: "dollarsign.circle.fill")!)
        newsView.setInit(tag: 3, text: "news", image: UIImage(systemName: "speaker.badge.exclamationmark.fill")!)
        membershipView.setInit(tag: 4, text: "memberShip", image: UIImage(systemName: "person.fill")!)
    }
}

接著到ViewController,裡面拉一個UIView並繼承剛剛長條的TabBar

https://ithelp.ithome.com.tw/upload/images/20230920/20140368EdtZ6cBEv9.png#### 接著把五個畫面的ViewController都建立出來,這樣就可以了!
程式碼:


import UIKit

class MainViewController: BaseViewController {
    
    // MARK: - IBOutlet
    
    @IBOutlet weak var ccontainer: UIView!
    
    // MARK: - Variables
    
    
    @IBOutlet weak var CustomTabBar: CustomTabBar!
    
    private var homeViewController = HomeViewController()
    private var findingViewController = FindingViewController()
    private var walletViewController = WalletViewController()
    private var newsViewController = NewsViewController()
    private var memberShipViewController = MemberShipViewController()
    var vc: [UIViewController] = []
    var nowVC: Int = BottomItems.HomeViewController.rawValue
    
    // MARK: - LifeCycle
    
    override func viewDidLoad() {
        super.viewDidLoad()
        vc = [homeViewController, findingViewController, walletViewController, newsViewController, memberShipViewController]
        updateView(0)

        CustomTabBar.buttonTapped = {
            let page = $0
            if $0 != self.nowVC {
                self.pageChange(page: $0)
        }
    }
    
    // MARK: - UI Settings
    
    func pageChange(page: Int) {
        self.updateView(page)
    }
    
    private func updateView(_ index: Int) {
        nowVC = index
        if children.first(where: { String(describing: $0.classForCoder) == String(describing: vc[index].classForCoder) }) == nil {
            addChild(vc[index])
            vc[index].view.frame = ccontainer.bounds
        }
        ccontainer.addSubview(vc[index].view ?? UIView())
    }
    
}

結果:

https://ithelp.ithome.com.tw/upload/images/20230920/20140368PVaI6uYFYT.png
以上就是今天的內容了~


上一篇
Day4: iOS 開發:基本畫面建構 - BaseViewController
下一篇
Day6: iOS 開發:頁面的排版 - Layout
系列文
App從開發到上架30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言